package reflect;

import java.lang.reflect.Method;
import java.util.Scanner;

/**
 * java反射机制
 * 反射是java中的动态机制，它允许我们在程序运行期间再确定类的实例化，方法的调用，
 * 属性的调用等，而不是传统意义上的在编码期间确定。
 *
 * 因此，反射可以大大的提高代码的灵活度，但是随之而来的是更多的系统开销和较慢的
 * 运行速度，因此不能过度的依赖反射。
 */
public class ReflectDemo1 {
    public static void main(String[] args) throws ClassNotFoundException {
        /*
            Class类
            Class的每一个实例用于表示JVM加载的一个类，所以我们也称Class的实例
            为类的类对象。
            当JVM加载一个类时会同时实例化一个Class的实例与之对应，这个Class实例
            中会保存该类的一切信息(类名，有哪些方法，构造器，属性，注解等等)
            我们在程序运行期间通过某个类的类对象来操作这个类。因此使用反射操作某个
            类的第一件事就是获取该类的类对象

            获取一个类的类对象有三种方式:
            1:类名.class
            例如:
            Class cls = String.class;
            Class cls = int.class (基本类型只能通过这种方式获取类对象)

            2:Class.forName(String className)
            通过Class的静态方法forName，传入对应类的完全限定名(包名.类名)的
            形式获取类对象
            Class cls = Class.forName("java.lang.String");

            3:通过类加载器ClassLoader加载类对象

         */

        //获取String的类对象
//        Class cls = String.class;

        /*
            Class.forName()
            该方法要求必须处理异常:ClassNotFoundException

            当指定的字符串(对应类的完全限定名)有误时会抛出该异常，或指定的
            路径下无法找到该类时也会抛出该异常(多发生于通过反射加载第三方
            jar文件里的类，有时我们忘记将该jar导入环境变量中，导致JVM无法
            通过正确的包路径找到它)。
         */
//        Class cls = Class.forName("java.lang.String");

        /*
            类加载器ClassLoader
            类加载器有很多中不同的实现，创建方式也各不相同。
            最常用的是如下方式:
            ClassLoader loader = 当前类.class.getClassLoader();
            类加载器除了可以加载类对象，还可以做很多和环境变量相关的操作，功能多。
         */
        ClassLoader classLoader = ReflectDemo1.class.getClassLoader();
//        Class cls = classLoader.loadClass("java.lang.String");
        /*
            java.lang.String
            java.lang.Integer
            java.util.ArrayList
            java.util.HashMap
            reflect.Person
         */
        System.out.println("请输入一个类名:");
        Scanner scanner = new Scanner(System.in);
        String input = scanner.nextLine();
        Class cls = classLoader.loadClass(input);

        //查看类名
        //获取类的完全限定名(包名.类名)
        String className = cls.getName();
        System.out.println("类名:"+className);
        //仅获取类名
        className = cls.getSimpleName();
        System.out.println("类名:"+className);

        //通过类对象获取其表示的类的所有方法
        //获取所有公开方法和从超类继承的方法
//        Method[] methods = cls.getMethods();
//        for(Method method : methods){
//            System.out.println(method.getName());
//        }

        //获取本类定义的方法(包含私有方法，但是不含有从超类继承的方法)
        Method[] methods = cls.getDeclaredMethods();
        for(Method method : methods){
            System.out.println(method.getName());
        }
    }
}


